#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdlib>
#include <netinet/in.h>
#include <string>
#include <pthread.h>
#include <arpa/inet.h>
#include <strings.h>

enum
{
    USAGE_ERR,
    SOCKET_ERR,
    BIND_ERR
};
namespace udpclient
{
    using namespace std;

    class client
    {
    public:
        client(string ip, uint16_t port)
            : _sock(-1), _ip(ip), _port(port)
        {
        }
        ~client()
        {
            close(_sock);
        }

        void init()
        {
            _sock = socket(AF_INET, SOCK_DGRAM, 0);
            if (_sock == -1)
            {
                cerr << "socket error" << endl;
                exit(SOCKET_ERR);
            }
            // 客户端的套接字不需要我们显式绑定
        }

        // void start()
        // {
        //     // 构造服务端的网络地址
        //     struct sockaddr_in sever;
        //     sever.sin_addr.s_addr = inet_addr(_ip.c_str());
        //     sever.sin_family = AF_INET;
        //     sever.sin_port = htons(_port);
        //     socklen_t severlen = sizeof sever;
        //     while (1)
        //     {
        //         string message;
        //         cout << "Please Enter:";
        //         // cin>>message; //会被空格中断
        //         getline(cin, message); // 读取一行

        //         sendto(_sock, message.c_str(), message.size(), 0, (struct sockaddr *)&sever, severlen);

        //         // 接收服务器的返回结果
        //         char buf[1024];
        //         bzero(buf, 1024);
        //         struct sockaddr_in from;
        //         socklen_t fromlen =sizeof from;
        //         recvfrom(_sock, buf, sizeof buf - 1, 0, (struct sockaddr*)&from,&fromlen);
        //         string response = buf;
        //         string ip = inet_ntoa(from.sin_addr);
        //         uint16_t port = ntohs(from.sin_port);
        //         cout<<"response from " <<ip <<":"<<port <<"----"<<response<<endl;
        //     }
        // }

        void start()
        {
            // 构造服务端的网络地址
            struct sockaddr_in sever;
            sever.sin_addr.s_addr = inet_addr(_ip.c_str());
            sever.sin_family = AF_INET;
            sever.sin_port = htons(_port);
            socklen_t severlen = sizeof sever;
            pthread_t tid;
            pthread_create(&tid, nullptr, clientReceive, (void *)&_sock);
            // 主线程读取和发送消息
            while (1)
            {
                string message;
                cout << "Please Enter:";
                getline(cin, message); // 读取一行
                sendto(_sock, message.c_str(), message.size(), 0, (struct sockaddr *)&sever, severlen);
                usleep(1000);
            }
            pthread_join(tid, nullptr);
        }
        static void *clientReceive(void *arg)
        {
            int sock = *(static_cast<int *>(arg));
            while (1)
            {
                char buf[1024];
                struct sockaddr_in from;
                socklen_t len = sizeof from;
                int n = recvfrom(sock, buf, sizeof(buf) - 1, 0, (struct sockaddr *)&from, &len);
                if (n > 0)
                {
                    buf[n] = 0;
                    cout << buf << endl;
                }
            }
        }

    private:
        int _sock;
        uint16_t _port;
        string _ip;
    };

}